package controllers

import (
	"log"
	"net/http"
	"strconv"

	"gitee.com/yanxingshuyuan/backend/util"

	"gitee.com/yanxingshuyuan/backend/server/models"

	"gitee.com/yanxingshuyuan/backend/server/repositories"
	"github.com/gin-gonic/gin"
)

// NoteController serves note info
type NoteController struct {
	Repo  *repositories.NoteRepo
	IDGen *util.N64Generator
}

func NewNoteController(r *repositories.NoteRepo) *NoteController {
	return &NoteController{
		Repo:  r,
		IDGen: util.NewN64Generator(8),
	}
}

func (ctrl *NoteController) Star(c *gin.Context) {
	var note models.ONote
	if err := c.ShouldBindJSON(&note); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	if note.MID == "" {
		c.JSON(http.StatusBadRequest, gin.H{"status": "failed", "error": "invalid mid"})
		return
	}
	delta := note.Value
	if delta > 1 {
		delta = 1
	}
	if delta < -1 {
		delta = -1
	}
	note.Value = delta
	// 新建操作
	if note.ID == 0 {
		// gen note id
		user, _ := c.Get("jwtuser")
		note.PID = user.(*models.User).Pid
		log.Printf("Note to Add: %v\n", note)
		if succ := ctrl.Repo.AddNoteOld(&note); succ {
			c.JSON(http.StatusOK, note)
		} else {
			c.JSON(http.StatusBadRequest, gin.H{"status": "failed", "id": note.ID})
		}
	} else {
		// 获取当前星级
		stars := ctrl.Repo.GetStars(note.ID)
		note.Value = stars + note.Value
		if note.Value > 0 {
			ctrl.Repo.UpdateStars(note.ID, delta)
		} else {
			ctrl.Repo.RemoveNote(note.ID)
		}
		c.JSON(http.StatusOK, note)
	}

}

func (ctrl *NoteController) AddNote(c *gin.Context) {
	var note models.NoteForm
	if err := c.ShouldBindJSON(&note); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	// gen note id
	user, _ := c.Get("jwtuser")
	note.Uploader = user.(*models.User).Pid
	if note.Author == "" {
		note.Author = note.Uploader
	}
	log.Printf("Note to Add: %#v\n", note)
	if succ := ctrl.Repo.AddNote(&note); succ {
		c.JSON(http.StatusOK, gin.H{"status": "ok", "id": note.Mat.ID})
	} else {
		c.JSON(http.StatusBadRequest, gin.H{"status": "failed", "id": note.Mat.ID})
	}
}

func (ctrl *NoteController) ModifyNote(c *gin.Context) {
	var note models.ONote
	if err := c.ShouldBindJSON(&note); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	if ok := ctrl.Repo.ModifyNote(&note); ok {
		c.JSON(http.StatusOK, "")
	} else {
		c.JSON(http.StatusBadRequest, gin.H{"error": "failed to modify note"})
	}
}

func (ctrl *NoteController) RemoveNote(c *gin.Context) {
	idtext := c.Param("noteid")
	id, err := strconv.ParseInt(idtext, 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, "noteid should be int64")
	}
	ctrl.Repo.RemoveNote(id)
	c.JSON(http.StatusOK, gin.H{"status": "ok"})
}

func (ctrl *NoteController) ListMyNotes(c *gin.Context) {
	user, _ := c.Get("jwtuser")
	pid := user.(*models.User).Pid
	mid := c.Query("mid")
	notes := ctrl.Repo.ListNotesForPid(pid, mid)
	c.JSON(http.StatusOK, notes)
}

func (ctrl *NoteController) ListMyStarsForArticle(c *gin.Context) {
	user, _ := c.Get("jwtuser")
	pid := user.(*models.User).Pid
	var artids []string
	err := c.ShouldBindJSON(&artids)
	if err != nil {
		c.JSON(http.StatusBadRequest, artids)
	}
	notes := ctrl.Repo.ListStarsForArticles(pid, artids)
	c.JSON(http.StatusOK, notes)
}

func (ctrl *NoteController) ListMyStarsForMat(c *gin.Context) {
	user, _ := c.Get("jwtuser")
	pid := user.(*models.User).Pid
	var mids []int64
	err := c.ShouldBindJSON(&mids)
	if err != nil {
		c.JSON(http.StatusBadRequest, mids)
	}
	notes := ctrl.Repo.ListStarsForMat(pid, mids)
	c.JSON(http.StatusOK, notes)
}

func (ctrl *NoteController) ListAllNotes(c *gin.Context) {
	colid := c.Query("colid")
	artid := c.Query("artid")
	notes := ctrl.Repo.ListNotes(colid, artid)
	c.JSON(http.StatusOK, notes)
}

func (ctrl *NoteController) ListNoteCards(c *gin.Context) {
	mid := c.Query("mid")

	/*
		scope, err := strconv.Atoi(c.Query("scope"))
		if err != nil {
			c.JSON(http.StatusBadRequest, "scope字段不是数字")
			return
		}

		lineStr := c.Query("line")
		line, err := strconv.Atoi(lineStr)
		if err != nil {
			c.JSON(http.StatusBadRequest, "line字段不是数字")
			line = -1
		}
	*/
	cards := ctrl.Repo.ListNotesForPid("", mid)
	c.JSON(http.StatusOK, cards)
}

func (ctrl *NoteController) ListSectionsForScope(c *gin.Context) {
	// scope, err := strconv.Atoi(c.Query("scope"))
	// if err != nil {
	// c.JSON(http.StatusBadRequest, "scope字段不是数字")
	// return
	// }
	sections := ctrl.Repo.ListAllSections()
	c.JSON(http.StatusOK, sections)
}
